package com.zmn.plat.business.impl.company;

import com.alibaba.fastjson.JSON;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto.VtDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.map.MapUtils;
import com.zmn.common.utils.map.Point;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.plat.business.interfaces.company.BaseCompanyBService;
import com.zmn.plat.common.constant.CompanyConsts;
import com.zmn.plat.common.dictionary.PlatEnum;
import com.zmn.plat.common.dictionary.PlatErrorCodeDict;
import com.zmn.plat.common.dto.company.BaseCompanyDIO;
import com.zmn.plat.common.dto.company.CompanyDRO;
import com.zmn.plat.common.dto.company.CompanyTypeDIO;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.manager.interfaces.cache.CompanyCache;
import com.zmn.plat.model.entity.company.BaseCompany;
import com.zmn.plat.model.entity.company.BaseCompanyQuery;
import com.zmn.plat.model.entity.company.CompanyTypeQuery;
import com.zmn.plat.model.vo.company.BaseCompanyVO;
import com.zmn.plat.model.vo.company.area.BaseCompanyAreaVO;
import com.zmn.plat.services.interfaces.area.BaseAreaService;
import com.zmn.plat.services.interfaces.company.BaseCompanyAreaService;
import com.zmn.plat.services.interfaces.company.BaseCompanyService;
import com.zmn.plat.services.interfaces.product.ServProductRelationService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.utils.bean.BeanCopyUtils;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author duanzuocai
 * @version v1.0
 * @since 2018/10/16 14:59
 */
@Slf4j
@Service
public class BaseCompanyBServiceImpl implements BaseCompanyBService {

    @Resource
    CompanyCache companyCache;
    @Resource
    private BaseAreaService baseAreaService;
    @Resource
    private BaseCompanyAreaService baseCompanyAreaService;
    @Resource
    private BaseCompanyService baseCompanyService;
    @Resource
    private ServProductService servProductService;
    @Resource
    private ServProductRelationService servProductRelationService;

    private final String CREATER = "B_SERVICE";
    private static final String COMPANY_CNHB = "川南环保";
    private static final String COMPANY_JXH = "家修汇";

    @Override
    public List<CompanyDRO> listZmnAllInfomationCompany() {
        BaseCompanyQuery query = new BaseCompanyQuery();
        query.setPlat(GlobalConsts.PLAT_MARK_ZMN);
        query.setType(CompanyConsts.COMPANY_TYPE_SERVICE);
        query.setChildType(CompanyConsts.COMPANY_TYPE_SERVICE_OCO);
        List<BaseCompany> comps = baseCompanyService.listByQuery(query);

        // 禁用掉的数据
        List<BaseCompany> disableCompany = this.filterDisableCompany(comps);
        comps.removeAll(disableCompany);
        List<BaseCompany> disableUpdateTime = this.filterDisableCompanyByUpdateTime(disableCompany);
        comps.addAll(disableUpdateTime);
        ArrayList<CompanyDRO> companyDroList = this.getCompanyDroList(comps);
        return companyDroList;
    }

    @Override
    public List<CompanyDRO> listZmnAllElectricCompany() {
        BaseCompanyQuery query = new BaseCompanyQuery();
        query.setPlat(GlobalConsts.PLAT_MARK_ZMN);
        query.setType(CompanyConsts.COMPANY_TYPE_ELECTRIC);
        query.setChildType(CompanyConsts.COMPANY_TYPE_CHILD_DEFAULT);
        List<BaseCompany> comps = baseCompanyService.listByQuery(query);

        List<BaseCompany> disableCompany = this.filterDisableCompany(comps);
        comps.removeAll(disableCompany);
        List<BaseCompany> disableUpdateTime = this.filterDisableCompanyByUpdateTime(disableCompany);
        comps.addAll(disableUpdateTime);
        ArrayList<CompanyDRO> companyDroList = this.getCompanyDroList(comps);
        return companyDroList;
    }

    @Override
    public List<VtDTO> listCompanyVtByPage(Integer pageNum, Integer pageSize) {
        if (NumberUtil.isNullOrZero(pageNum) || NumberUtil.isNullOrZero(pageSize)) {
            log.error("分页参数不能为空");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        pageSize = pageSize > 500 ? 500 : pageSize;
        BaseCompanyQuery query = new BaseCompanyQuery();
        query.setPageSize(pageSize);
        query.setPageIndex(pageNum);
        query.setPagesNumber(pageNum);
        List<BaseCompanyVO> baseCompanyVOS = baseCompanyService.listPageByQuery(query, null);

        if (CollectionUtils.isEmpty(baseCompanyVOS)) {
            return Collections.emptyList();
        }

        List<VtDTO> dros = baseCompanyVOS.stream().map(baseCompanyVO -> new VtDTO(baseCompanyVO.getCompanyId(), baseCompanyVO.getName(), baseCompanyVO.getStatus())).collect(Collectors.toList());

        return dros;
    }

    @Override
    public List<CompanyDRO> listAllCompanyInfoByPage(Integer pageNum, Integer pageSize) {
        if (NumberUtil.isNullOrZero(pageNum) || NumberUtil.isNullOrZero(pageSize)) {
            log.error("分页参数不能为空");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        pageSize = pageSize > 500 ? 500 : pageSize;
        BaseCompanyQuery query = new BaseCompanyQuery();
        query.setPageSize(pageSize);
        query.setPageIndex(pageNum);
        query.setPagesNumber(pageNum);
        List<BaseCompanyVO> baseCompanyVOS = baseCompanyService.listPageByQuery(query, null);

        if (CollectionUtils.isEmpty(baseCompanyVOS)) {
            return Collections.emptyList();
        }

        List<CompanyDRO> allCompany = baseCompanyVOS.stream().map(baseCompany -> {
            CompanyDRO companyDRO = new CompanyDRO();
            BeanUtils.copyProperties(baseCompany, companyDRO);
            return companyDRO;
        }).collect(Collectors.toList());

        return allCompany;
    }

    @Override
    public List<CompanyDRO> listCompanyByTypesUpdate(List<CompanyTypeDIO> types, Integer plat, Integer month) {
        log.info("listCompanyByTypesUpdate参数types：{}，plat：{}，month：{}", types, plat, month);
        if (CollectionUtils.isEmpty(types)) {
            log.error("公司类型不能为空");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        List<CompanyTypeQuery> companyTypeQueryList = types.stream().map(companyTypeDIO -> new CompanyTypeQuery(companyTypeDIO.getType(), companyTypeDIO.getChildType())).collect(Collectors.toList());

        // 默认两个月
        if (NumberUtil.isNullOrZero(month)) {
            month = 2;
        }

        List<CompanyDRO> companyResult = this.listCompanyByTypes(types, plat);

        List<CompanyDRO> collect =
            Optional.ofNullable(baseCompanyService.listCompanyByUpdateTime(this.getMonthsAgo(month), companyTypeQueryList, plat)).orElse(Collections.emptyList()).stream().map(mm -> {
                CompanyDRO companyDRO = new CompanyDRO();
                BeanUtils.copyProperties(mm, companyDRO);
                return companyDRO;
            }).collect(Collectors.toList());
        companyResult.addAll(collect);

        return companyResult;
    }

    @Override
    @SuppressWarnings("Duplicates")
    public List<CompanyDRO> listPageByQuery(BaseCompanyDIO dio, Integer staffId) {
        if (Objects.isNull(dio)) {
            log.error("dio参数不能为空");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        List<BaseCompanyVO> baseCompanyList = this.listPageVoByQuery(dio, staffId);

        List<CompanyDRO> companyDROS = baseCompanyList.stream().map(baseCompany -> {
            CompanyDRO companyDRO = new CompanyDRO();
            BeanUtils.copyProperties(baseCompany, companyDRO);
            return companyDRO;
        }).collect(Collectors.toList());

        return companyDROS;
    }

    @Override
    public List<VtDTO> listVtPageByQuery(BaseCompanyDIO dio, Integer staffId) {
        if (Objects.isNull(dio)) {
            log.error("dio参数不能为空");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        List<BaseCompanyVO> voList = this.listPageVoByQuery(dio, staffId);

        List<VtDTO> dros = voList.stream().map(baseCompanyVO -> new VtDTO(baseCompanyVO.getCompanyId(), baseCompanyVO.getName())).collect(Collectors.toList());

        return dros;
    }


    private List<BaseCompanyVO> listPageVoByQuery(BaseCompanyDIO dio, Integer staffId) {
        BaseCompanyQuery query = new BaseCompanyQuery();
        BeanCopyUtils.copyProperties(dio, query);

        List<CompanyTypeDIO> companyTypeQueryList = dio.getCompanyTypeQueryList();
        if (!CollectionUtils.isEmpty(companyTypeQueryList)) {
            List<CompanyTypeQuery> queryList = companyTypeQueryList.stream().map(companyTypeDIO -> {
                CompanyTypeQuery typeQuery = new CompanyTypeQuery();
                BeanUtils.copyProperties(companyTypeDIO, typeQuery);
                return typeQuery;
            }).collect(Collectors.toList());
            query.setCompanyTypeQueryList(queryList);
        }

        if (NumberUtil.isPositiveInteger(staffId)) {
            query.setOperatorId(staffId);
        }

        query.setPageSize(NumberUtil.isNullOrZero(dio.getPageSize()) || dio.getPageSize() > 1500 ? 1500 : dio.getPageSize());
        query.setPagesNumber(NumberUtil.isNullOrZero(dio.getPagesNumber()) ? 1 : dio.getPagesNumber());
        query.setPageIndex(query.getPagesNumber());

        List<BaseCompanyVO> baseCompanyList = baseCompanyService.listPageByQuery(query, staffId);
        dio.setTotalCount(query.getTotalCount());
        dio.setPageIndex(query.getPageIndex());
        dio.setPageSize(query.getPageSize());
        return baseCompanyList;
    }

    private List<Point> turntoPoint(ArrayList<Map> mapPoints) {
        List<Point> points = new ArrayList<>();

        mapPoints.forEach(map -> {
            points.add(new Point(map.get("lng").toString(), map.get("lat").toString()));
        });

        return points;
    }

    @SuppressWarnings("Duplicates")
    private List<CompanyDRO> listCompanyByTypes(List<CompanyTypeDIO> companyTypeDIOList, Integer plat) {
        List<CompanyTypeQuery> types = companyTypeDIOList.stream().map(companyTypeDIO -> new CompanyTypeQuery(companyTypeDIO.getType(), companyTypeDIO.getChildType())).collect(Collectors.toList());

        BaseCompanyQuery query = new BaseCompanyQuery();
        query.setPlat(plat);
        query.setCompanyTypeQueryList(types);
        query.setStatus(GlobalConsts.YES);

        List<CompanyDRO> collect = Optional.ofNullable(baseCompanyService.listVOByQuery(query)).orElse(Collections.emptyList()).stream().map(mm -> {
            CompanyDRO companyDro = new CompanyDRO();
            BeanUtils.copyProperties(mm, companyDro);
            return companyDro;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public int insertCompanyAndOrgan(BaseCompany company) {
        int result = baseCompanyService.insert(company);

        Integer plat = company.getPlat();

        PlatEnum enumPlat = PlatEnum.getEnumByPlat(plat);

        int subCompanyOrgId = enumPlat.subCompanyOrgId;

        log.info("[zmn]insertCompanyAndOrgan 添加公司, 结果：{}, {}", result, company);

        return result;
    }

    @Override
    public Boolean checkBylatlngAndBaseCompanyAreaList(List<BaseCompanyAreaVO> baseCompanyAreaList, Double longitude, Double latitude) {
        BaseCompanyAreaVO baseCompanyAreaVO;
        for (int i = 0; i < baseCompanyAreaList.size(); i++) {
            baseCompanyAreaVO = baseCompanyAreaList.get(i);
            if (baseCompanyAreaVO.getMapDataType() == MapUtils.BAIDU_MAP_TYPE_POLYGON) {
                if (Objects.isNull(baseCompanyAreaVO.getMapData())) {
                    return false;
                }

                ArrayList<Map> mapPoints = (ArrayList<Map>)JSON.parseArray(baseCompanyAreaVO.getMapData(), Map.class);
                Point toPoint = new Point(longitude, latitude);
                List<Point> points = turntoPoint(mapPoints);
                boolean result = MapUtils.isInPolygon(toPoint, points);
                if (result) {
                    return true;
                }
            } else if (baseCompanyAreaVO.getMapDataType() == MapUtils.BAIDU_MAP_TYPE_CIRCLE) {
                if (Objects.isNull(baseCompanyAreaVO.getMapData())) {
                    return false;
                }

                double size = Double.parseDouble(baseCompanyAreaVO.getMapData());
                boolean result = MapUtils.inCircle(latitude, longitude, size, Double.valueOf(baseCompanyAreaVO.getLatitude()), Double.valueOf(baseCompanyAreaVO.getLongitude()));
                if (result) {
                    return true;
                }
            } else {
                return true;
            }
        }

        return false;
    }

    @SuppressWarnings("Duplicates")
    @Override
    public List<BaseCompanyAreaVO> findBylatlngAndBaseCompanyAreaList(List<BaseCompanyAreaVO> baseCompanyAreaVOListAll, Double longitude, Double latitude) {
        List<BaseCompanyAreaVO> baseCompanyAreaVOList = new ArrayList<>();

        baseCompanyAreaVOListAll.stream().forEach(baseCompanyAreaVO -> {
            if (baseCompanyAreaVO.getMapDataType() == MapUtils.BAIDU_MAP_TYPE_POLYGON) {
                if (!StringUtils.isEmpty(baseCompanyAreaVO.getMapData())) {
                    ArrayList<Map> mapPoints = (ArrayList<Map>)JSON.parseArray(baseCompanyAreaVO.getMapData(), Map.class);
                    Point toPoint = new Point(longitude, latitude);
                    List<Point> points = turntoPoint(mapPoints);
                    boolean result = MapUtils.isInPolygon(toPoint, points);
                    if (result) {
                        baseCompanyAreaVOList.add(baseCompanyAreaVO);
                    }
                }
            } else if (baseCompanyAreaVO.getMapDataType() == MapUtils.BAIDU_MAP_TYPE_CIRCLE) {
                if (!StringUtils.isEmpty(baseCompanyAreaVO.getMapData())) {
                    double size = Double.parseDouble(baseCompanyAreaVO.getMapData());
                    boolean result = MapUtils.inCircle(latitude, longitude, size, Double.valueOf(baseCompanyAreaVO.getLatitude()), Double.valueOf(baseCompanyAreaVO.getLongitude()));
                    if (result) {
                        baseCompanyAreaVOList.add(baseCompanyAreaVO);
                    }
                }
            } else {
                baseCompanyAreaVOList.add(baseCompanyAreaVO);
            }
        });

        return baseCompanyAreaVOList;
    }

    @Override
    public BaseCompanyVO getSubCompanyByServiceCompanyId(Integer serviceCompanyId) {
        if (NumberUtil.isNullOrZero(serviceCompanyId)) {
            log.error("服务公司ID不能为空,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        BaseCompanyVO serviceComapny = baseCompanyService.findByKey(serviceCompanyId);

        if (Objects.isNull(serviceComapny)) {
            log.error("服务公司不存在,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_SERVICE_COMPANY_NOT_EXIST);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_SERVICE_COMPANY_NOT_EXIST);
        }

        if (NumberUtil.isNullOrZero(serviceComapny.getSubCompanyId())) {
            log.error("服务公司没有关联的子公司信息,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_SERVICE_COMPANY_HAS_NO_RELATED_SUB_COMPANY);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_SERVICE_COMPANY_HAS_NO_RELATED_SUB_COMPANY);
        }

        BaseCompanyVO subCompany = baseCompanyService.findByKey(serviceComapny.getSubCompanyId());

        if (Objects.isNull(subCompany)) {
            log.error("服务公司关联的子公司不存在,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_SERVICE_COMPANY_RELATED_SUB_COMPANY_NOT_EXIST);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_SERVICE_COMPANY_RELATED_SUB_COMPANY_NOT_EXIST);
        }

        return subCompany;
    }

    private List<BaseCompany> listCompanyByAreaAndRelationIds(List<BaseCompanyAreaVO> baseCompanyAreaList, Double longitude, Double latitude) {
        List<Integer> companyIdList = new ArrayList<>();

        baseCompanyAreaList.stream().forEach(baseCompanyAreaVO -> {
            if (baseCompanyAreaVO.getMapDataType() == null) {
                companyIdList.add(baseCompanyAreaVO.getManageCompanyId());
                return;
            }
            if (baseCompanyAreaVO.getMapDataType() == MapUtils.BAIDU_MAP_TYPE_POLYGON) {
                if (Objects.nonNull(baseCompanyAreaVO.getMapData()) && Objects.nonNull(longitude) && Objects.nonNull(latitude)) {
                    ArrayList<Map> mapPoints = (ArrayList<Map>)JSON.parseArray(baseCompanyAreaVO.getMapData(), Map.class);
                    Point toPoint = new Point(longitude, latitude);
                    List<Point> points = turntoPoint(mapPoints);
                    boolean result = MapUtils.isInPolygon(toPoint, points);
                    if (result) {
                        companyIdList.add(baseCompanyAreaVO.getManageCompanyId());
                    }
                }
            } else if (baseCompanyAreaVO.getMapDataType() == MapUtils.BAIDU_MAP_TYPE_CIRCLE) {
                if (!StringUtils.isEmpty(baseCompanyAreaVO.getMapData()) && !StringUtils.isEmpty(baseCompanyAreaVO.getLatitude()) && !StringUtils.isEmpty(baseCompanyAreaVO.getLatitude())) {
                    double size = Double.parseDouble(baseCompanyAreaVO.getMapData());
                    boolean result = MapUtils.inCircle(latitude, longitude, size, Double.valueOf(baseCompanyAreaVO.getLatitude()), Double.valueOf(baseCompanyAreaVO.getLongitude()));
                    if (result) {
                        companyIdList.add(baseCompanyAreaVO.getManageCompanyId());
                    }
                }
            } else {
                companyIdList.add(baseCompanyAreaVO.getManageCompanyId());
            }
        });

        if (CollectionUtils.isEmpty(companyIdList)) {
            return Collections.EMPTY_LIST;
        }

        List<BaseCompany> baseCompanyList = baseCompanyService.findByKeys(companyIdList, CompanyConsts.COMPANY_TYPE_SERVICE, CompanyConsts.COMPANY_TYPE_SERVICE_OCO, GlobalConsts.YES);
        baseCompanyList = CollectionUtils.isEmpty(baseCompanyList) ? new ArrayList<>() : baseCompanyList;
        List<BaseCompany> baseCompanyListServ = baseCompanyService.findByKeys(companyIdList, CompanyConsts.COMPANY_TYPE_SERVICE, CompanyConsts.COMPANY_TYPE_SERVICE_NOT_OCO, GlobalConsts.YES);
        if (!CollectionUtils.isEmpty(baseCompanyListServ)) {
            baseCompanyList.addAll(baseCompanyListServ);
        }

        return baseCompanyList;
    }


    /**
     * 描述: 过滤公司状态为禁用的数据
     *
     * @param comps
     *            通过组织架构关联出来的公司信息
     * @return java.util.List<com.zmn.plat.model.entity.company.BaseCompany>
     **/
    private List<BaseCompany> filterDisableCompany(List<BaseCompany> comps) {

        return Optional.ofNullable(comps).orElse(Collections.emptyList()).stream().filter(Objects::nonNull).filter(ff -> Objects.equals(ff.getStatus(), GlobalConsts.NO)).distinct()
            .collect(Collectors.toList());
    }

    /**
     * 描述: 过滤公司状态为禁用的数据并且修改时间大于 前2个月的数据
     *
     * @param disableComps
     *            通过组织架构关联出来的公司信息 已禁用掉的部分
     * @return java.util.List<com.zmn.plat.model.entity.company.BaseCompany>
     **/
    private List<BaseCompany> filterDisableCompanyByUpdateTime(List<BaseCompany> disableComps) {

        return Optional.ofNullable(disableComps).orElse(Collections.emptyList()).stream().filter(Objects::nonNull).filter(ff -> Objects.nonNull(ff.getUpdateTime()))
            .filter(ff -> ff.getUpdateTime().getTime() >= this.getMonthsAgo(2).getTime()).distinct().collect(Collectors.toList());
    }

    /**
     * 描述: 格式转化,排除 ERP 算账不包含“川南环保”和“家修汇”
     *
     * @param comps
     *            通过组织价格加载出来的公司数据
     * @return java.util.ArrayList<com.zmn.plat.dubbo.dto.company.CompanyDRO>
     * @updater wangjie 代码重写
     **/
    @NotNull
    private ArrayList<CompanyDRO> getCompanyDroList(List<BaseCompany> comps) {

        return Optional.ofNullable(comps).orElse(Collections.emptyList()).stream().filter(ff -> !Objects.equals(COMPANY_CNHB, ff.getName())).filter(ff -> !Objects.equals(COMPANY_JXH, ff.getName()))
            .distinct().map(mm -> BeanMapper.map(mm, CompanyDRO.class)).collect(Collectors.toCollection(ArrayList::new));
    }

    /**
     * 描述: 获取前2个月第一天数据
     *
     * @return java.lang.String
     **/
    private Date getMonthsAgo(int month) {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, 0 - month);
        int lastMonthMaxDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        c.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH), lastMonthMaxDay, 23, 59, 59);
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-01  00:00:00");
        // 上上月第一天
        return DateUtil.parse(sdf2.format(c.getTime()));
    }
}
